package com.example.lotterysystem.service.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;
import com.example.lotterysystem.common.utils.RedisUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.controller.param.ShowWinningRecordsParam;
import com.example.lotterysystem.dao.dataobject.*;
import com.example.lotterysystem.dao.mapper.*;
import com.example.lotterysystem.service.DrawPrizeService;
import com.example.lotterysystem.service.dto.WinningRecordDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.example.lotterysystem.common.config.DirectRabbitConfig.*;

@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {
    private final static Logger logger= LoggerFactory.getLogger(DrawPrizeServiceImpl.class);

    private final String WINNING_RECORDS_PREFIX="WINNING_RECORDS_";
    private final  Long WINNING_RECORDS_TIMEOUT=60*60*24*2L;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ActivityMapper activityMapper;

@Autowired
private ActivityPrizeMapper activityPrizeMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private PrizeMapper prizeMapper;
@Autowired
private WinningRecordMapper winningRecordMapper;

    @Override
    public void drawPrize(DrawPrizeParam param) {
        // 创建一个Map对象，用于存储消息ID和消息数据
        Map<String,String> map = new HashMap<>();
        // 生成一个随机的消息ID
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        // 将参数转换为JSON字符串
        map.put("messageData", JacksonUtil.writeValueAsString(param));
       // 将消息发送到指定的交换机和路由键
       rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
       // 记录日志，表示消息发送成功
       logger.info("mq消息发送成功：Map：{}",JacksonUtil.writeValueAsString(map));
    }

    /**
     * 校验抽奖参数
     * @param param
     */
    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {
        ActivityDO activityDO= activityMapper.selectById(param.getActivityId());
        ActivityPrizeDO activityPrizeDO=activityMapper.selectPrizeById(
                param.getPrizeId(), param.getActivityId());
        //校验活动或奖品是否存在
        if(activityDO==null||activityPrizeDO==null){
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NOT_EXIST);
            logger.info("效验抽奖请求失败：{}",
                    ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NOT_EXIST.getMessage());
            return false;
        }

        //校验活动是否有效
        if(activityDO.getStatus()
                .equalsIgnoreCase(ActivityStatusEnum.FINISHED.name())){
//            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_FINISHED);
            logger.info("效验抽奖请求失败：{}",ServiceErrorCodeConstants.ACTIVITY_FINISHED.getMessage());
        return false;
        }
        //校验奖品是否有效
        if(activityPrizeDO.getStatus()
                .equalsIgnoreCase(ActivityPrizeStatusEnum.FINISHED.name())){
//            throw new ServiceException(ServiceErrorCodeConstants.PRIZE_FINISHED);
            logger.info("效验抽奖请求失败：{}",ServiceErrorCodeConstants.PRIZE_FINISHED.getMessage());
        return false;
        }


        //效验中奖人数和奖品数量是否相等
       if(activityPrizeDO.getPrizeAmount()!=param.getWinnerList().size()){
//           throw new ServiceException(ServiceErrorCodeConstants.PRIZE_WINNER_SIZE_ERROR);
           logger.info("效验抽奖请求失败：{}",
                   ServiceErrorCodeConstants.PRIZE_WINNER_SIZE_ERROR.getMessage());
       return false;
       }
return true;
    }

    /**
     * 保存中奖者名单
     *
     * @param param
     * @return
     */
    @Override
    public List<WinningRecordDO> saveWinnerList(DrawPrizeParam param) {
        //查询相关信息，活动，奖品，人员,活动关联奖品表
ActivityDO activityDO=activityMapper.selectById(param.getActivityId());
List<UserDO>userDOList=userMapper.batchSelectByIds(
        param.getWinnerList()
                .stream()
                .map(DrawPrizeParam.Winner::getUserId)
                .collect(Collectors.toList()));
        PrizeDO prizeDO = prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDO activityPrizeDO =
                activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        //构建中奖者记录，保存
List<WinningRecordDO>winningRecordDOList=userDOList.stream()
        .map(userDO->{
            WinningRecordDO winningRecordDO = new WinningRecordDO();
        winningRecordDO.setActivityId(param.getActivityId());
        winningRecordDO.setPrizeId(param.getPrizeId());
        winningRecordDO.setActivityName(activityDO.getActivityName());
        winningRecordDO.setPrizeName(prizeDO.getName());
        winningRecordDO.setPrizeTiers(activityPrizeDO.getPrizeTiers());
        winningRecordDO.setWinnerId(userDO.getId());
        winningRecordDO.setWinnerName(userDO.getUserName());
        winningRecordDO.setWinnerPhone(userDO.getPhoneNumber());
        winningRecordDO.setWinnerEmail(userDO.getEmail());
        winningRecordDO.setWinningTime(param.getWinningTime());
            return winningRecordDO;
        }).collect(Collectors.toList());
logger.warn("中奖者记录：{}",winningRecordDOList);
winningRecordMapper.batchInsert(winningRecordDOList);
        //缓存中奖者记录
        //1.缓存奖品维度中奖记录(WinningRecord_activity_prizeId,winningRecordDOList)
cacheWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),
        winningRecordDOList,
        WINNING_RECORDS_TIMEOUT);

        //2.缓存活动维度中奖记录（WinningRecord_activityId,winningRecordDOList(活动维度的中奖名单)）
if(activityDO.getStatus()
        .equalsIgnoreCase(ActivityStatusEnum.FINISHED.name())){
    //查询活动维度的全量中奖记录

    List<WinningRecordDO>allList=winningRecordMapper.selectByActivityId(param.getActivityId());

    logger.warn("活动层面要缓存的数据："+allList);
    cacheWinningRecords(String.valueOf(param.getActivityId()),
            allList,
            WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDOList;
    }

    @Override
    public void deleteList(Long activityId, Long prizeId) {
        if(null==activityId ){
            logger.warn("删除中奖者名单参数为空！activityId:{},prizeId:{}",activityId,prizeId);
            return;
        }
        //删除表数据
        winningRecordMapper.deleteWinnerList(activityId,prizeId);


        //删除缓存（奖品维度，活动维度）
        if(null !=prizeId){
            deleteWinnerRecords(activityId+"_"+prizeId);
        }
        //无论是否传递了prizeId，都删除活动维度的缓存
        //如果传递了prizeId，证明奖品未抽奖，必须删除活动维度1的缓存记录
        //如果没有传递prizeId，则删除活动维度的缓存
        deleteWinnerRecords(String.valueOf(activityId));

    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParam param) {
        //查询redis：奖品，活动
        String key=null==param.getPrizeId()
                ?String.valueOf(param.getActivityId())
                :param.getActivityId()+"_"+param.getPrizeId();
        List<WinningRecordDO>winningRecordDOList=getWinningRecords(key);
        if(!CollectionUtils.isEmpty(winningRecordDOList)){
            return convertToWinningRecordDTOList(winningRecordDOList);
        }

                //如果redis不存在，查库
        winningRecordDOList=winningRecordMapper.selectByActivityIdOrPrizeId(
                param.getActivityId(), param.getPrizeId());
        if(CollectionUtils.isEmpty(winningRecordDOList)){
            logger.info("查询中奖记录为空！param:{}",
                    JacksonUtil.writeValueAsString(param));
            return Arrays.asList();
        }
                //存放记录到redis
        cacheWinningRecords(key,
                winningRecordDOList,
                WINNING_RECORDS_TIMEOUT);
                return convertToWinningRecordDTOList(winningRecordDOList);
            }

    private List<WinningRecordDTO> convertToWinningRecordDTOList(
            List<WinningRecordDO> winningRecordDOList) {
        if(CollectionUtils.isEmpty(winningRecordDOList)){
            return Arrays.asList();
        }
        return winningRecordDOList.stream()
                .map(winningRecordDO->{
                    WinningRecordDTO winningRecordDTO = new WinningRecordDTO();
                    winningRecordDTO.setWinnerId(winningRecordDO.getWinnerId());
                    winningRecordDTO.setWinnerName(winningRecordDO.getWinnerName());
                    winningRecordDTO.setPrizeName(winningRecordDO.getPrizeName());
                    winningRecordDTO.setPrizeTiers(
                            ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTiers()));
                    winningRecordDTO.setWinningTime(winningRecordDO.getWinningTime());
                    return winningRecordDTO;
        }).collect(Collectors.toList());
    }

    private void deleteWinnerRecords(String s) {
        try{
            redisUtil.hasKey(WINNING_RECORDS_PREFIX+s);
            redisUtil.delete(WINNING_RECORDS_PREFIX+s);
        }catch (Exception e){
            logger.error("删除缓存中奖记录异常！Key:{}",WINNING_RECORDS_PREFIX+s);
        }
    }

    /**
     * 缓存中奖记录
     * @param key
     * @param winningRecordDOList
     * @param time
     */
    private void cacheWinningRecords(String key,
                                     List<WinningRecordDO> winningRecordDOList,
                                     Long time) {
        String str="";
        try{
            if(!StringUtils.hasText(key)||
                    CollectionUtils.isEmpty(winningRecordDOList)){
                logger.warn("缓存中奖记录为空！Key:{},value:{}",key,JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }

            str=JacksonUtil.writeValueAsString(winningRecordDOList);
            redisUtil.set(WINNING_RECORDS_PREFIX+key,
                   str,
                    time);
        }catch (Exception e){
            logger.error("缓存中奖记录异常！Key:{},value:{}",WINNING_RECORDS_PREFIX+key,str);
        }
    }

    /**
     * 从缓存中获取中奖记录
     * @param key
     * @return
     */
    private List<WinningRecordDO> getWinningRecords(String key) {
        try{
            if(!StringUtils.hasText(key)){
                logger.warn("获取缓存中奖记录为空！Key:{}",key);
                return Arrays.asList();
            }

            String str = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if (!StringUtils.hasText(str)) {
                return Arrays.asList();
            }
            List<WinningRecordDO>winningRecordDOList = JacksonUtil.readListValue(str, WinningRecordDO.class);
            logger.info("从缓存中获取中奖记录"+winningRecordDOList);
            return winningRecordDOList;
        }catch (Exception e){
            logger.error("获取缓存中奖记录异常！Key:{}",WINNING_RECORDS_PREFIX+key);
            return Arrays.asList();
        }

    }



}
